﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ChemicalEquilibrium
{
    /// <summary>
    /// 激活失活平衡反应
    /// </summary>
    public class ReactActivate
    {
        public Queue<Reactant> As, A_s, Cs, C_s;
        public int ActivateVelocity, InactivateVelocity;
        int ActivateParameter, InactivateParameter;
        int ActivateEfficiency, InactivateEfficiency;

        public int GetACount() { return this.As.Count; }
        public int GetA_Count() { return this.A_s.Count; }
        public int GetCCount() { return this.Cs.Count; }
        public int GetC_Count() { return this.C_s.Count; }
        public int GetActivateVelocity() { return this.ActivateVelocity; }
        public int GetInactivateVelocity() { return this.InactivateVelocity; }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="As">激活的A</param>
        /// <param name="A_s">失活的A</param>
        /// <param name="Cs">失活剂</param>
        /// <param name="C_s">激活剂</param>
        /// <param name="activateParameter">激活速度参数 : [1, 100]</param>
        /// <param name="inactivateParameter">失活速度参数 : [1, 100]</param>
        /// <param name="activateEfficiency">酶的激活效率参数 : [1, 100]</param>
        /// <param name="inactivateEfficiency">酶的失活效率参数 : [1, 100]</param>
        public ReactActivate(Queue<Reactant> As, Queue<Reactant> A_s, Queue<Reactant> Cs, Queue<Reactant> C_s, int activateParameter, int inactivateParameter, int activateEfficiency, int inactivateEfficiency)
        {
            this.As = As;
            this.A_s = A_s;
            this.Cs = Cs;
            this.C_s = C_s;
            this.ActivateParameter = activateParameter;
            this.InactivateParameter = inactivateParameter;
            this.ActivateEfficiency = activateEfficiency;
            this.InactivateEfficiency = inactivateEfficiency;

            if (As == null || A_s == null) throw new Exception("React Error : Reactant is null!");
        }

        /// <summary>
        /// 激活反应
        ///     A_ + (C_) -> A + (C_)
        /// </summary>
        public void Activate()
        {
            if (this.C_s != null)
            {
                if (this.A_s.Count * this.C_s.Count == 0)
                    this.ActivateVelocity = 0;
                else if (this.A_s.Count * this.C_s.Count * this.ActivateEfficiency / (this.A_s.Count + this.C_s.Count * this.ActivateEfficiency) < this.ActivateParameter)
                    this.ActivateVelocity = 1;
                else
                    this.ActivateVelocity = this.A_s.Count * this.C_s.Count * this.ActivateEfficiency / (this.A_s.Count + this.C_s.Count * this.ActivateEfficiency) / this.ActivateParameter;
            }
            else
                this.ActivateVelocity = (this.A_s.Count + this.ActivateParameter - 1) / this.ActivateParameter;

            for (int i = 0; i < this.ActivateVelocity; i++)
            {
                if (this.A_s.Count == 0) break;

                this.As.Enqueue(this.A_s.Dequeue());
            }
        }

        /// <summary>
        /// 灭活反应
        ///     A + (C_) -> A_ + (C_)
        /// </summary>
        public void Inactivate()
        {
            if (this.Cs != null)
            {
                if (this.As.Count * this.Cs.Count == 0) return;

                int count = this.As.Count * this.Cs.Count * this.InactivateEfficiency / (this.As.Count + this.Cs.Count * this.InactivateEfficiency);

                if (count < this.InactivateParameter)
                    this.InactivateVelocity = Math.Min(this.As.Count, this.Cs.Count);
                //this.InactivateVelocity = count;
                else
                    this.InactivateVelocity = count / this.InactivateParameter;
            }
            else
                this.InactivateVelocity = (this.As.Count + this.InactivateParameter - 1) / this.InactivateParameter;

            for (int i = 0; i < this.InactivateVelocity; i++)
            {
                if (this.As.Count == 0) break;

                this.A_s.Enqueue(this.As.Dequeue());
            }
        }
    }
}
